using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using IOUtils;
using System.Collections;

namespace PListUtil
{
    class PropertyList
    {
        //$OffsetSize, $ObjRefSize, $NumObjects, $TopObject, $OffsetTableOffset
        public static Int32 offsetSize;
        public static Int32 objRefSize;
        public static Int32 numObjects;
        public static Int32 topObject;
        public static Int32 offsetTableOffset;
        public static ArrayList XML;

        
        public static String[] BinaryPListToXML(Byte[] Data) {
            MemoryStream stream = new MemoryStream(Data);
            BinaryReaderES reader = new BinaryReaderES(stream);
            // Set Endian-nes (BigEndian)
            reader.swap = true;
            // Make sure that this is a binary plist...
            Char[] check = new Char[6];
            Int32 bytes = reader.Read(check, 0, 6);
            if ( check.ToString() != "bplist" ) {
                // Not a binary plist
                return null;
            }
            // last 32 bits of the file contain the startup info that we need.
            long offset = stream.Length - 32;
            stream.Position = offset + 6;
            offsetSize = Convert.ToInt32(reader.ReadChar());
            objRefSize = Convert.ToInt32(reader.ReadChar());
            stream.Position = stream.Position + 4;
            numObjects = reader.ReadInt32();
            stream.Position = stream.Position + 4;
            topObject = reader.ReadInt32();
            stream.Position = stream.Position + 4;
            offsetTableOffset = reader.ReadInt32();

            // Start reading the objects
            Byte[] offsetTable = new Byte[numObjects * offsetSize];
            // Get the Offset Table
            Console.WriteLine("stop");
            Int32[] objOffsets = GetObjectOffsets(Data, offsetTableOffset, numObjects);
            Console.WriteLine("stop");
            for ( Int32 i = 0; i < numObjects; i++ ) {
                stream.Position = objOffsets[i];
                GetObject(Data, objOffsets[i]);


            }
            stream.Dispose();
            return null;
        }

        internal static Int32[] GetObjectOffsets(Byte[] data, Int32 offSet, Int32 numObjects) {
            MemoryStream stream = new MemoryStream(data);
            BinaryReaderES reader = new BinaryReaderES(stream);
            reader.swap = true;
            stream.Position = offSet;
            Int32[] offsets = new Int32[numObjects];
            for ( Int32 i = 0; i < numObjects; i++ ) {
                offsets[i] = Convert.ToInt32(reader.ReadInt16());
            }
            stream.Dispose();
            reader = null;
            return offsets;
        }

        internal static void GetObject(byte[] data, Int32 offSet) {
            MemoryStream stream = new MemoryStream(data);
            BinaryReaderES reader = new BinaryReaderES(stream);
            reader.swap = true;
            stream.Position = offSet;
            Byte objHeaderByte = reader.ReadByte();
            Int32 objectLength = objHeaderByte & 0xF;
            Int32 objType = objHeaderByte / 0x10;
            Console.WriteLine(objectLength.ToString());
            if ( objType != 0 && objectLength == 15 ) {
                GetObject(data, offSet + 1);
            }
            /*
            switch ( objType ) {
                case 1:
                    ReadInteger(reader, objectLength);
                    break;
                case 2:
                    ReadReal(reader, objectLength);
                    break;
                case 5:
                    ReadString(reader, objectLength);
                    break;
                case 6:
                    ReadUString(reader, objectLength);
                    break;
                case 10:
                    ReadArray(reader, objectLength);
                    break;
                case 13:
                    ReadDict(reader, objectLength);
                    break;
            }
             */
        }

        internal static Byte[] ReadBytes(Byte[] data, Int32 offset, Int32 bytes) {
            Byte[] retVal = new Byte[bytes];
            for ( Int32 i = 0; i < bytes; i++ ) {
                retVal[i] = data[i + offset];
            }
            return retVal;
        }
    }
}
